package com.atguigu.consumer;

import com.atguigu.constant.MqConst;
import com.atguigu.constant.RedisConst;
import com.atguigu.entity.SeckillProduct;
import com.atguigu.entity.UserSeckillSkuInfo;
import com.atguigu.service.SeckillProductService;
import com.atguigu.utils.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.Date;
import java.util.List;

@Component
public class SeckillConsumer {

    @Autowired
    SeckillProductService seckillProductService;
    @Autowired
    RedisTemplate redisTemplate;
    //扫描符合的秒杀商品
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = MqConst.SCAN_SECKILL_QUEUE,durable = "false"),
            exchange = @Exchange(value = MqConst.SCAN_SECKILL_EXCHANGE,durable = "false",autoDelete = "true"),
            key = {MqConst.SCAN_SECKILL_ROUTE_KEY}))
    public void scanSeckillProductToRedis(Message message, Channel channel) throws Exception{
        //1.扫描数据库符合秒杀的商品
        QueryWrapper<SeckillProduct> wrapper = new QueryWrapper<>();
        //1为秒杀商品 2为结束 3审核未通过
        wrapper.eq("status",1);
        //剩余库存数>0
        wrapper.gt("num",0);
        //取出当前时间当日商品
        wrapper.eq("DATE_FORMAT(start_time,'%Y-%m-%d')", DateUtil.formatDate(new Date()));
        List<SeckillProduct> seckillProductList = seckillProductService.list(wrapper);
        if (!CollectionUtils.isEmpty(seckillProductList)){
            for (SeckillProduct seckillProduct : seckillProductList) {
                //2.判断缓存中是否已经有该秒杀商品
                boolean flag = redisTemplate.boundHashOps(RedisConst.SECKILL_PRODUCT).hasKey(seckillProduct.getSkuId().toString());
                if (flag){
                    //如果有就不再执行本轮循环
                    continue;
                }
                //3.没有该秒杀商品就把它放入缓存
                redisTemplate.boundHashOps(RedisConst.SECKILL_PRODUCT).put(seckillProduct.getSkuId().toString(), seckillProduct);
                //4.利用list的数据结构存储库存数量 减库存的时候吐出一个 防止超卖
                for (int i = 0; i < seckillProduct.getNum(); i++) {
                    redisTemplate.boundListOps(RedisConst.SECKILL_STOCK_PREFIX +seckillProduct.getSkuId())
                            .leftPush(seckillProduct.getSkuId().toString());
                }
                //5.通知redis集群中其他节点该商品可以进行秒杀了 状态位  发布订阅模式
                redisTemplate.convertAndSend(RedisConst.PREPARE_PUB_SUB_SECKILL,seckillProduct.getSkuId()+":"+RedisConst.CAN_SECKILL);
            }
            // 手动确认
            channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
        }
    }

    //2.预下单之后才能判断用户是否有抢购资格
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = MqConst.PREPARE_SECKILL_QUEUE,durable = "false"),
            exchange = @Exchange(value = MqConst.PREPARE_SECKILL_EXCHANGE,durable = "false",autoDelete = "true"),
            key = {MqConst.PREPARE_SECKILL_ROUTE_KEY}
    ))
    public void prepareSeckill(UserSeckillSkuInfo userSeckillSkuInfo, Message message, Channel channel) throws Exception{
        if(userSeckillSkuInfo!=null){
            //开始处理预下单
            seckillProductService.prepareSeckill(userSeckillSkuInfo);
        }
        // 手动ack
        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
    }


}
